#include "log.hpp"
class ThreadData
{
public:
    ThreadData(int sockfd, string ip, uint16_t port)
        : sockfd_(sockfd),
          ip_(ip),
          port_(port)
    {
    }
    int sockfd_;
    string ip_;
    uint16_t port_;
};


void transService(int sockfd, string ip, uint16_t port)//转成大写服务
{
    assert(sockfd > 0);
    assert(!ip.empty());
    assert(port >= 1024);

    char buffer[BUFFER_SIZE];
    while (1)
    {
        ssize_t s = read(sockfd, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            buffer[s] = 0;
            if (strcasecmp(buffer, "quit") == 0)
            {
                logMessage(DEBUG, "client quit -- %s[%d]", ip.c_str(), port);
                break;
            }
            logMessage(DEBUG, "trans before:%s[%d]>>>%s", ip.c_str(), port, buffer);
            for (int i = 0; i < s; i++)
                buffer[i] = toupper(buffer[i]);
            logMessage(DEBUG, "trans after:%s[%d]>>>%s", ip.c_str(), port, buffer);
            write(sockfd, buffer, strlen(buffer));
        }
        else if (s == 0)
        {
            logMessage(DEBUG, "client quit:%s[%d]", ip.c_str(), port);
            break;
        }
        else
        {
            logMessage(DEBUG, "%s[%d] read:%s", ip.c_str(), port, strerror(errno));
            break;
        }
    }
    close(sockfd);
    logMessage(DEBUG, "server close %d done", sockfd);
}


void *threadRoutine(void *argc)
{
    ThreadData *td = static_cast<ThreadData *>(argc);
    transService(td->sockfd_, td->ip_, td->port_);
    delete td;
    return nullptr;
}

class tcpServer
{
public:
    tcpServer(uint16_t port, string ip)
        : port_(port), ip_(ip), listenSock_(-1)
    {
    }
    ~tcpServer() {}

    void init()
    {
        // 1.创建套接字
        listenSock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenSock_ < 0)
        {
            logMessage(FATAL, "socket: %s ", strerror(errno));
            exit(SOCKET_ERR);
        }
        logMessage(DEBUG, "socket: %s ", strerror(errno));
        // 2. bind
        // 2.1 填充信息到结构体
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 2.2 bind,本地sock写入内核sock
        if (bind(listenSock_, (const struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind: %s", strerror(errno));
            exit(BIND_ERR);
        }
        logMessage(DEBUG, "bind: %s,%d", strerror(errno), listenSock_);

        // 3.监听
        if (listen(listenSock_, 5) < 0)
        {
            logMessage(FATAL, "listen: %s", strerror(errno));
            exit(LISTEN_ERR);
        }
        logMessage(DEBUG, "listen: %s,%d", strerror(errno), listenSock_);
    }

    void start()
    {
        while (1)
        {
            // signal(SIGCHLD,SIG_IGN);
            //  4.连接
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            int serviceSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if (serviceSock < 0)
            {
                logMessage(WARINING, "accept:%s[%d]", strerror(errno), serviceSock);
                continue;
            }
            // 4.1获取客户端基本信息
            uint16_t peerPort = ntohs(peer.sin_port);
            string ip = inet_ntoa(peer.sin_addr);
            logMessage(DEBUG, "accept :%s |%s[%d],sockfd:%d", strerror(errno), ip.c_str(), peerPort, serviceSock);
            // 5.提供服务：转成大写
            // 单进程版本
            // transService(serviceSock, ip, peerPort);

            // 多进程版本  忽略SIGCHLD信号
            //  pid_t id=fork();
            //  assert(id!=-1);
            //  if(id==0)
            //  {
            //      close(listenSock_);
            //      transService(serviceSock, ip, peerPort);
            //      exit(0);
            //  }
            //  close(serviceSock);//避免文件描述符资源泄漏

            // 多进程版本  创建孙子进程，退出父进程，让系统回收孤儿进程
            // pid_t id = fork();
            // assert(id != -1);
            // if (id == 0)
            // {
            //     close(listenSock_);
            //     if (fork() > 0)
            //         exit(0);
            //     // 孙子进程提供服务
            //     transService(serviceSock, ip, peerPort);
            //     exit(0);
            // }
            // pid_t ret=waitpid(id,nullptr,0);
            // assert(ret>0);
            // (void )ret;
            ThreadData *td = new ThreadData(serviceSock, ip, peerPort);
            pthread_t tid;
            pthread_create(&tid, nullptr, threadRoutine, (void *)td);
        }
    }

private:
    int listenSock_; // 监听套接字
    uint16_t port_;  // 端口号
    string ip_;      // ip地址
};
int main(int argc, char *argv[])
{
    if (argc != 2 && argc != 3)
    {
        cout << "Usage:\n\t" << argv[0] << " port [ip]" << endl;
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    string ip;
    if (argc == 3)
        ip = argv[2];
    tcpServer ts(port, ip);
    ts.init();
    ts.start();
    return 0;
}